#ifndef _BLASR_STAT_UTILS_HPP_
#define _BLASR_STAT_UTILS_HPP_

#include <math.h>
#include <stdlib.h>
#include <limits.h>
#include <time.h>
#include <vector>
#include <algorithm>
#include <assert.h>

static const long FactorialTableLength = 21;

static const long long FactorialTable[] = {
    1L, //0
    1L, //1
    2L, //2
	6L, //3
	24L,//4
	120L, //5
	720L, //6
	5040L, //7
	40320L,//8
	362880L, //9
	3628800L,//10
	39916800L,//11
	479001600L,//12
	6227020800LL,//13
	87178291200LL,//14
	1307674368000LL,//15
	20922789888000LL,//16
	355687428096000LL,//17
	6402373705728000LL,//18
	121645100408832000LL,//19
	2432902008176640000LL//20
};

static const float qnorm[] = { 
    0.00,  0.00250,  0.00501,  0.00751,  0.0100248,  0.0125393,  0.0150457,
    0.0175408,  0.0200506,  0.0225647,  0.0250611, 0.0275717, 
    0.0300891,  0.0325931,  0.0351088,  0.0376059,  0.0401181,
    0.0426244,  0.0451313,  0.0476466,  0.0501537,  0.0526685,
    0.0551768,  0.0576842,  0.0601966,  0.0627038,  0.0652137,
    0.0677392,  0.0702467,  0.0727575,  0.0752699,  0.0777852,
    0.080295,  0.0828113,  0.0853292,  0.0878418,  0.0903688,
    0.0928765,  0.095392,  0.0979195,  0.10043,  0.102954,
    0.105478,  0.107994,  0.110512,  0.113035,  0.115563,
    0.118083,  0.120607,  0.123137,  0.125664,  0.128186,
    0.130713,  0.133244,  0.135772,  0.138305,  0.140837,
    0.143367,  0.145904,  0.14843,  0.150967,  0.153507,
    0.15604,  0.158573,  0.161116,  0.163651,  0.166199,
    0.168748,  0.171287,  0.173822,  0.176371,  0.178922,
    0.181467,  0.184019,  0.186569,  0.189112,  0.19167,
    0.194223,  0.196777,  0.199337,  0.201891,  0.204451,
    0.207017,  0.209579,  0.212134,  0.214704,  0.217263,
    0.219839,  0.222406,  0.224971,  0.227549,  0.230116,
    0.232695,  0.235260,  0.237849,  0.240428,  0.243002,
    0.245581,  0.248173,  0.250756,  0.25334,  0.255933,
    0.258520,  0.261118,  0.26371,  0.266315,  0.268900,
    0.271509,  0.274117,  0.276717,  0.279314,  0.281921,
    0.284532,  0.287145,  0.289754,  0.292374,  0.294996,
    0.29761,  0.300232,  0.302859,  0.305487,  0.308105,
    0.310732,  0.313366,  0.316003,  0.318635,  0.321276,
    0.323913,  0.326563,  0.329201,  0.331857,  0.334502,
    0.337157,  0.339807,  0.342461,  0.345122,  0.347787,
    0.350451,  0.353119,  0.355785,  0.358454,  0.361132,
    0.363806,  0.366484,  0.36917,  0.371855,  0.374543,
    0.377232,  0.379927,  0.382624,  0.385328,  0.388027,
    0.39072,  0.393437,  0.396148,  0.398857,  0.401579,
    0.404289,  0.407016,  0.409731,  0.412465,  0.415197,
    0.417922,  0.420666,  0.423403,  0.426148,  0.428892,
    0.431646,  0.434391,  0.437152,  0.439914,  0.442672,
    0.44544,  0.448219,  0.450981,  0.45376,  0.45654,
    0.459323,  0.462117,  0.464905,  0.467698,  0.470491,
    0.473297,  0.476105,  0.478915,  0.48172,  0.484549,
    0.487361,  0.490189,  0.493015,  0.495853,  0.498682,
    0.501528,  0.504372,  0.507226,  0.510075,  0.512938,
    0.515798,  0.518651,  0.521522,  0.524401,  0.527279,
    0.530169,  0.533049,  0.53594,  0.53883,  0.541737,
    0.544649,  0.547551,  0.550462,  0.553383,  0.556308,
    0.559237,  0.562176,  0.565104,  0.568053,  0.570997,
    0.573953,  0.576911,  0.579874,  0.582846,  0.585819,
    0.588790,  0.591776,  0.594768,  0.597768,  0.600759,
    0.60376,  0.606775,  0.60979,  0.612817,  0.615842,
    0.618879,  0.621914,  0.624957,  0.62800,  0.631069,
    0.63412,  0.637195,  0.640264,  0.643347,  0.646437,
    0.649525,  0.652621,  0.655723,  0.658838,  0.661952,
    0.665073,  0.668203,  0.671345,  0.674482,  0.677636,
    0.680795,  0.683962,  0.68713,  0.690304,  0.69349,
    0.696681,  0.699881,  0.703089,  0.706308,  0.709528,
    0.712753,  0.715985,  0.719224,  0.722473,  0.725735,
    0.729009,  0.73227,  0.73555,  0.738844,  0.74214,
    0.745449,  0.748769,  0.752081,  0.75541,  0.758751,
    0.762107,  0.765458,  0.768822,  0.772195,  0.775574,
    0.778965,  0.782367,  0.785774,  0.789192,  0.792612,
    0.796053,  0.799507,  0.802953,  0.80642,  0.809898,
    0.813384,  0.816873,  0.820371,  0.823897,  0.827412,
    0.830958,  0.83449,  0.838056,  0.841624,  0.84519,
    0.848787,  0.852385,  0.855992,  0.859611,  0.86325,
    0.866898,  0.870544,  0.874213,  0.877899,  0.881584,
    0.885292,  0.889005,  0.892736,  0.896476,  0.900224,
    0.903991,  0.907766,  0.91156,  0.915364,  0.91918,
    0.92301,  0.926854,  0.93071,  0.93458,  0.938479,
    0.94237,  0.946296,  0.950225,  0.954165,  0.958123,
    0.962092,  0.966083,  0.970097,  0.97411,  0.978152,
    0.98220,  0.986279,  0.990355,  0.994453,  0.99857,
    1.00271,  1.00686,  1.01103,  1.01522,  1.01942,
    1.02365,  1.02789,  1.03215,  1.03643,  1.04073,
    1.04504,  1.04938,  1.05374,  1.05812,  1.06251,
    1.06693,  1.07137,  1.07583,  1.08031,  1.08482,
    1.08934,  1.09389,  1.09846,  1.10306,  1.10768,
    1.11232,  1.11698,  1.12167,  1.12639,  1.13113,
    1.13589,  1.14068,  1.14550,  1.15034,  1.15522,
    1.16011,  1.16504,  1.17000,  1.17498,  1.18000,
    1.18504,  1.19011,  1.19522,  1.20035,  1.20552,
    1.21072,  1.21596,  1.22122,  1.22652,  1.23186,
    1.23723,  1.24264,  1.24808,  1.25356,  1.25908,
    1.26464,  1.27023,  1.27587,  1.28155,  1.28727,
    1.29303,  1.29883,  1.30468,  1.31057,  1.31651,
    1.32250,  1.32853,  1.33462,  1.34075,  1.34693,
    1.35317,  1.35946,  1.36580,  1.37220,  1.37865,
    1.38517,  1.39174,  1.39837,  1.40507,  1.41183,
    1.41865,  1.42554,  1.43250,  1.43953,  1.44663,
    1.45380,  1.46105,  1.46838,  1.47579,  1.48328,
    1.49085,  1.49851,  1.50626,  1.51410,  1.52203,
    1.53006,  1.53819,  1.54643,  1.55477,  1.56322,
    1.57178,  1.58046,  1.58926,  1.59819,  1.60724,
    1.61643,  1.62576,  1.63523,  1.64485,  1.65462,
    1.66456,  1.67466,  1.68494,  1.69539,  1.70604,
    1.71688,  1.72793,  1.73919,  1.75068,  1.76241,
    1.77438,  1.78661,  1.79911,  1.81191,  1.82500,
    1.83842,  1.85217,  1.86629,  1.88079,  1.89569,
    1.91103,  1.92683,  1.94313,  1.95996,  1.97736,
    1.99539,  2.01409,  2.03352,  2.05374,  2.07485,
    2.09692,  2.12007,  2.14441,  2.17009,  2.19728,
    2.22621,  2.25712,  2.29036,  2.32634,  2.36561,
    2.40891,  2.45726,  2.51214,  2.57582,  2.65206,
    2.74778,  2.87816,  3.09023,  10000};


inline int Choose(int a, int b);

void InitializeRandomGenerator(int value);

template<typename T>
void MeanVar(std::vector<T> &values, float &mean, float &var);

inline void InitializeRandomGeneratorWithTime() {
	time_t t;
    srandom((unsigned) time(&t));
}

unsigned int RandomUnsignedInt(unsigned int randMax);

unsigned int RandomInt(int randMax);

unsigned int RandomInt(unsigned int min, unsigned int max);

float Random();

bool FindQNorm(float prob, float &nStdDev);

#include "StatUtilsImpl.hpp"

#endif
